# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         testsuite_set_task.py
# Description:  批量执行测试场景集
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2020/12/28 9:51
# -------------------------------------------------------------------------------
import logging
import threading

from celery import shared_task

from apps.BasicAuthService.models import User
from apps.CeleryScheduledTaskService.HttpAutoTestService.testsuite_task import exec_testsuite
from apps.CeleryScheduledTaskService.HttpAutoTestService.utils import send_testreport
from apps.HttpAutoTestService.core.http_client import HttpSession
from apps.HttpAutoTestService.core.http_session_context import HttpSessionContext
from apps.HttpAutoTestService.core.loader import load_ext_method_online
from apps.HttpAutoTestService.models import TestsuiteSet, TestsuiteResult
from utils.common import get_version

logger = logging.getLogger(__name__)


def exec_testsuite_set(testsuite_sets, executor, is_periodictask, version):
    """
    执行测试场景集
    Args:
        testsuite_sets: 被执行的场景集合集
        executor: 当前执行(登录)用户
        is_periodictask: 标记是否是定时任务
        version: 版本号

    Returns:

    """

    # 动态加载ext_method_online.py模块中内容
    ext_method_online_module, ext_methods_online = load_ext_method_online()

    for testsuite_set in testsuite_sets:
        logger.info('############### 执行测试场景集:【{name}】###############'.format(name=testsuite_set.name))
        # 1、创建HttpSession实例
        http_session = HttpSession()
        # 2、创建HttpSessionContext实例
        http_session_context = HttpSessionContext()

        # 获取场景集中的场景
        testsuite_set2testsuite_list = testsuite_set.testsuite_set2testsuite.all()

        for testsuite_set2testsuite in testsuite_set2testsuite_list:
            # 执行 / 跳过
            is_execute = testsuite_set2testsuite.is_execute
            if is_execute:
                # 循环次数
                loop_count = testsuite_set2testsuite.loop_count
                testsuites = [testsuite_set2testsuite.testsuite]
                for i in range(loop_count):
                    # 执行测试场景
                    exec_testsuite(testsuites=testsuites, executor=executor, is_periodictask=is_periodictask,
                                   version=version, http_session=http_session,
                                   http_session_context=http_session_context, is_testsuite_set=True,
                                   ext_method_online_module=ext_method_online_module,
                                   ext_methods_online=ext_methods_online)
        # 更新testsuite_set的状态
        testsuite_result_status_list = TestsuiteResult.objects.filter(
            testsuite_id__in=testsuite_set.testsuites.all(), version=version
        ).values_list('status', flat=True).order_by().distinct()
        if testsuite_result_status_list:
            if len(testsuite_result_status_list) == 1:
                testsuite_set.status = testsuite_result_status_list[0]
            else:
                testsuite_set.status = 'PARTIAL_PASS'
            testsuite_set.save()


@shared_task(name="批量执行测试场景集:HttpAutoTestService.testsuite_set_task.batch_exec_testsuite_set")
def batch_exec_testsuite_set(testsuite_sets=None, executor_id=None, is_periodictask=True, version=None):
    """
    批量执行测试场景集
    Args:
        testsuite_sets: 被执行的场景集id集合
        executor_id: 当前执行(登录)用户id
        is_periodictask: 标记是否是定时任务
        version: 版本号

    Returns:

    """
    # 获取执行者
    executor = User.objects.filter(id=executor_id, is_deleted=False).first()

    if version is None:
        # 执行定时任务时，参数version为None，此需要设置version；当批量执行时，参数version为传入值
        version = get_version()
    # 执行定时任务时，参数testsuite_sets类型为字符串，需要转换成列表；当批量执行时，参数testsuite_sets类型为列表
    if isinstance(testsuite_sets, str):
        testsuite_sets = eval(testsuite_sets) if isinstance(eval(testsuite_sets), list) else []
    testsuite_set_list = TestsuiteSet.objects.filter(id__in=testsuite_sets, is_deleted=False)

    # 启动线程数量
    threads_num = 5
    quotient, remainder = divmod(len(testsuite_set_list), threads_num)

    testsuite_sets_temp = [[] for i in range(threads_num)]
    for i in range(threads_num):
        testsuite_sets_temp[i] = testsuite_set_list[i * quotient:(i + 1) * quotient]

    for i in range(remainder):
        testsuite_sets_temp[i].append(testsuite_set_list[threads_num * quotient + i])

    threads = []
    for i in range(threads_num):
        t = threading.Thread(target=exec_testsuite_set,
                             args=(testsuite_sets_temp[i], executor, is_periodictask, version))
        threads.append(t)

    for t in threads:
        t.start()

    for t in threads:
        t.join()

    # 此处可以增加发送测试报告
    send_testreport(report_type='testsuite', version=version, executor=executor, is_periodictask=is_periodictask)

    return f"批量执行场景集已完成【用户ID：{executor_id}，场景集ID：{testsuite_sets}，是否是定时任务：{is_periodictask}，版本号：{version}】"
